#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <assert.h>
#include <unistd.h>
#include <sys/select.h>
#include <sys/poll.h>
#include <sys/epoll.h>
#include <sys/signal.h>

int stop_flag;
#define RUN_TIME 2

void timeout(int sig)
{
    stop_flag = 1;
}

int select_calls(int fd)
{
    int count = 0;
    int ret = 0;
    fd_set wset;
    fd_set w;

    FD_ZERO(&wset);
    FD_SET(fd, &wset);

    stop_flag = 0;
    alarm(RUN_TIME);
    while(!stop_flag)
    {
        w = wset;
        if (-1 == (ret=select(fd+1, NULL, &w, NULL, NULL)))
        {
            if (EINTR != errno)
            {
                fprintf(stderr, "%s fail: %d %s\n", __func__, errno, strerror(errno));
                return -1;
            }
        }
        else if (ret > 0)
        {
            count++;
        }
    }
    return count;
}

int poll_calls(int fd)
{
    int count = 0;
    int ret = 0;
    struct pollfd fds;

    fds.fd = fd;
    fds.events = POLLOUT;

    stop_flag = 0;
    alarm(RUN_TIME);
    while(!stop_flag)
    {
        if (-1 == (ret=poll(&fds, 1, 0)))
        {
            if (EINTR != errno)
            {
                fprintf(stderr, "%s fail: %d %s\n", __func__, errno, strerror(errno));
                return -1;
            }
        }
        else if (ret > 0)
        {
            count++;
        }
    }
    return count;
}

int epoll_calls(int fd)
{
    int count = 0;
    int ret = 0;
    int epfd;
    struct epoll_event event;

    epfd = epoll_create(1);
    assert(epfd > 0);
    event.events = EPOLLOUT;
    event.data.u32 = 0;
    ret = epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &event);
    if (ret == -1)
    {
        fprintf(stderr, "epoll_ctl fail:fd=%d errno=%d str=%s\n", fd, errno, strerror(errno));
        return -1;
    }

    stop_flag = 0;
    alarm(RUN_TIME);
    while(!stop_flag)
    {
        if (-1 == (ret=epoll_wait(epfd, &event, 1, -1)))
        {
            if (EINTR != errno)
            {
                fprintf(stderr, "%s fail: %d %s\n", __func__, errno, strerror(errno));
                return -1;
            }
        }
        else if (ret > 0)
        {
            count++;
        }
    }
    return count;
}

int main(int argc, char* argv[])
{
    int count;
    int high_fd = 0;
    int rw_fds[2];

    if (argc < 2)
    {
        fprintf(stderr, "usage: %s maxfd\n", argv[0]);
        return 1;
    }
    high_fd = atoi(argv[1]);
    if (high_fd < 1)
    {
        fprintf(stderr, "maxfd too short!\n");
        return 1;
    }

    if (-1 == pipe(rw_fds))
    {
        fprintf(stderr, "pipe fail: no=%d str=%s\n", errno, strerror(errno));
        return 1;
    }
    if (dup2(rw_fds[1], high_fd) != high_fd)
    {
        fprintf(stderr, "dup2 error: fd=%d, err=%d, str=%s\n", high_fd, errno, strerror(errno));
        return 1;
    }

    signal(SIGALRM, timeout);

    count = select_calls(high_fd);
    fprintf(stderr, "select() calls per second: %10d\n", count/RUN_TIME);

    count = poll_calls(high_fd);
    fprintf(stderr, "poll() calls per second:   %10d\n", count/RUN_TIME);

    count = epoll_calls(high_fd);
    fprintf(stderr, "epoll() calls per second:  %10d\n", count/RUN_TIME);

    return 0;
}


